#include "libclangmm/clangmm.hpp"
#include <string>
#include <memory>
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
#include <unordered_set>
#include <set>
#include <unordered_map>

using namespace std;

// class Project;
// class FieldDecl;
// class DeclType;

bool debug = false;
bool debugFunc = true;

std::unordered_map<std::string, bool> hasPointerMemberOfType;

std::unordered_set<std::string> fundamentalType = {
    "bool", "char", "short", 
    "int"
};

class FieldDecl {
public:
    std::string m_name;
    std::string m_type;
    bool m_isFundamentalType = false;
    bool m_isPointer = false;
    // bool m_hasPointerMember = false;
    bool hasPointerMember() const {
        return hasPointerMemberOfType[this->m_type];
    }
    // bool m_isReference;
    // bool m_isConst;
    friend ostream& operator<<(ostream &os, const FieldDecl & field) {
        os << field.m_type << " ";
        if(field.m_isPointer) {
            os << "*";
        }
        os << field.m_name << ";";
        return os;
    }
};

class DeclType {
public:
// friend bool compare(const DeclType &lhs, const DeclType &rhs);
    std::string m_typeName;
    // unsigned m_numOfMember = 0;
    std::vector<FieldDecl> m_fieldDecl;
    bool m_hasPointerMember = false;
    bool m_isFundamentalType = false;
    friend bool operator==(const DeclType &lhs, const DeclType &rhs) {
        return lhs.m_typeName == rhs.m_typeName;
    }
    friend bool operator<(const DeclType &lhs, const DeclType &rhs) {
        return lhs.m_typeName < rhs.m_typeName;
    }
    friend ostream& operator<<(ostream &os, const DeclType &declType) {
        // os << "Self-defined type: " << endl;
        os << "struct " + declType.m_typeName << " {" << endl;
        for(auto field : declType.m_fieldDecl) {
            os << "    " << field << endl;
        }
        os << "};" << endl;
        declType.m_hasPointerMember && os << "has_pointer_member" << endl;
        return os;
    }
};

class Project {
public:
    std::string m_projectName;
    // std::unordered_set<DeclType> m_declTypes;
    // std::unordered_set<int> m_decl;
    std::unordered_set<std::string> m_doneType;
    std::vector<DeclType> m_declTypes;
    // std::unordered_map<std::string, DeclType> m_declTypesMap;
    std::unordered_map<std::string, std::vector<std::pair<std::string, std::string>>> m_funcInArgs;
    std::unordered_map<std::string, std::pair<std::string, std::string>> m_funcReturnTypeAndName;
    std::unordered_map<std::string, std::string> m_alias2RealType;
};

Project project;
std::unordered_map<std::string, DeclType> types;
std::set<std::string> alreadyGeneratedPointerDrivingFunc;
std::set<std::string> alreadyGeneratedStructDrivingFunc;
std::unordered_map<std::string, std::string> symbolicFuncs;
std::vector<std::string> declarings;

/*
    MOCKER(func)
        .expects(atMost(3)) // 指定所有测试用例能调用的次数
        .with(eq(3))
        .will(returnValue(2))
        .then(returnValue(3))
        .then(invoke(mock_func));
*/

bool getIfStmt(const clangmm::Cursor &funcCursor, clangmm::Cursor &compoundStmtCursor)
{
    std::vector<clangmm::Cursor> child = funcCursor.get_children();
    auto it = find_if(child.cbegin(), child.cend(), [](clangmm::Cursor cursor){
        return cursor.get_kind() == clangmm::Cursor::Kind::IfStmt;
    });
    compoundStmtCursor = *it;
    return it != child.cend();
}

bool findAndMarkPointerMember(DeclType &declType)
{ // 可能有问题，后续处理!!!!!!
    debug && cout << "findAndMarkPointerMember of " << declType.m_typeName << endl;
    bool hasPointerMember = false;
    for(auto &field : declType.m_fieldDecl) {
        debug && cout << field.m_type << endl;
        if(field.m_isPointer) {
            hasPointerMember = true;
        }
        if(field.m_isFundamentalType) {
            continue;
        }
        auto type = types.find(field.m_type);
        if(type != types.cend()) {
            if(field.m_type == declType.m_typeName) { // 处理包含相同类型指针的情况，自包含放在之前的阶段处理。
                hasPointerMember = true;
                continue;
            }
            if(hasPointerMemberOfType.cend() == hasPointerMemberOfType.find(field.m_type)) {
                // if(hasPointerMemberOfType[field.m_type] = findAndMarkPointerMember(types[field.m_type])) {
                if(hasPointerMemberOfType[field.m_type] = findAndMarkPointerMember(type->second)) {
                // if(findAndMarkPointerMember(type->second)) {
                    debug && cout << "----------------------------+++++++++++++++++++++++++++" << endl;
                    hasPointerMember = true;
                }
            // } else if(field.m_hasPointerMember) { // !!!!!!!!!!!!!!!!!!!!!!!!
            } else if(hasPointerMemberOfType[field.m_type]) {
                debug && cout << "+++++++++++++++++++++++++++" << endl;
                hasPointerMember = true;
            }
            // debug && cout << "----------------------------+++++++++++++++++++++++++++" << endl;
        } else {
            debug && cout << "Encountered an unexposed type: " << field.m_type << endl;
        }
    }
    // hasPointerMember && declType.m_hasPointerMember = true;
    declType.m_hasPointerMember = hasPointerMember;
    hasPointerMember && debug && cout << declType.m_typeName + " has pointer member -----------" << endl;
    return hasPointerMember;
}

void procStructDecl(const clangmm::Cursor &structDeclCursor)
{
    debug && cout << "------------------procStructDecl()" << endl;
    std::string name = structDeclCursor.get_type_description();
    if(project.m_doneType.cend() != project.m_doneType.find(name)) {
        return;
    }
    DeclType declType;
    declType.m_typeName = name;
    queue<clangmm::Cursor> q;
    q.emplace(structDeclCursor);
    static int index = 0;
    while(!q.empty()) {
        clangmm::Cursor curFront = q.front();
        q.pop();

        // if(curFront.get_kind() == clangmm::Cursor::Kind::StructDecl) {
        //     declType.m_typeName = curFront.get_type_description();
        // }

        if(curFront.get_kind() == clangmm::Cursor::Kind::FieldDecl) {
            CXType ty = clang_getCursorType(curFront.cx_cursor);
            // std::string ttt = to_string(clang_getTypeSpelling(ty));
            // debug && cout << ttt << endl;
            // if(ty.kind == CXTypeKind::CXType_Invalid) {
            //     debug && cout << "Oops, encountered an unknown type, faked as : " << curFront.get_token_spelling() << endl;
            //     return;
            // }
            // clangmm::Cursor::Type type = curFront.get_type();
            // debug && cout << type.get_spelling() << endl;
            // if(type.cx_type.kind == CXTypeKind::CXType_Invalid) {
            //     debug && cout << "Oops, encountered an unknown type, faked as : " << curFront.get_token_spelling() << endl;
            //     return;
            // }
            // debug && cout << type.get_result().get_spelling() << endl;
            std::string memType = curFront.get_type_description();
            std::string memName = curFront.get_token_spelling();
            // debug && cout << memType + " " + memName << endl;
            FieldDecl fieldDecl;
            if(memType.back() == '*') {
                memType = memType.substr(0, memType.length() - 2);
                fieldDecl.m_isPointer = true;
                // fieldDecl.m_hasPointerMember = true; // ??????????
                // debug && cout << "isPointer of " << memType << endl;
            }
            fieldDecl.m_name = memName;
            fieldDecl.m_type = memType;
            if(fundamentalType.find(memType) !=  fundamentalType.cend()) {
                fieldDecl.m_isFundamentalType = true;
            }
            declType.m_fieldDecl.emplace_back(fieldDecl);
        }

        for(auto curTmp : curFront.get_children()) {
            q.emplace(curTmp);
        }
    }
    // if(project.m_declTypes.cend() == find(project.m_declTypes.cbegin(), project.m_declTypes.cend(), declType)) {
    // if(project.m_declTypes.cend() == project.m_declTypes.find(declType)) {
        debug && cout << declType << endl;
        project.m_doneType.emplace(declType.m_typeName);
        project.m_declTypes.emplace_back(declType);
        types.emplace(declType.m_typeName, declType);
        types.emplace("struct " + declType.m_typeName, declType);
        project.m_alias2RealType.emplace(declType.m_typeName, "struct " + declType.m_typeName);
    // }
}

std::string replace(const std::string &str, char from, char to)
{
    std::string toStr;
    toStr = str;
    for(auto &c : toStr) {
        c == from && (c = to);
    }
    return toStr;
}

/** 希望实现的功能：输入一个指向某个类型的指针，返回时，指针已经指向实际存储的内存空间，并且其中需要符号化的部分均已符号化了
 *  template版本搞不定，弃
 *  每个结构体对应一个符号化函数好了
 *  生成过的都用一个set数据结构记录一下
 *  
 * template<typename T>
 * T * makeMemberSymbolic()
 * {
 *      T *__1__ = new mem_type();
 *      klee_make_symbolic(&(__1__->_name), sizeof(_type), "_name");
 *      
 * }
 */
std::string getIndent()
{
    return "    ";
}

void makeSymbolicOfPointerType(const FieldDecl &field)
{ // recursive
    debug && cout << "makeSymbolicOfPointerType" << field << endl;
    std::string symbolicFunc = "\n";;
    DeclType type;
    if(field.m_isFundamentalType) {
        debug && cout << "TO-DO: BuiltInType" << endl;
        return;
    }
    std::string typeName = field.m_type;
    // auto aliasIter = project.m_alias2RealType.find(typeName);
    // if(project.m_alias2RealType.cend() != aliasIter) {
    //     typeName = aliasIter->second;
    //     debug && cout << "alias of " << typeName << ": " << field.m_type << endl;
    // }
    auto typeIter = types.find(typeName);
    if(types.cend() != typeIter) {
        std::string varName = "__" + replace(typeName, ' ', '_');
        if(alreadyGeneratedPointerDrivingFunc.cend() != alreadyGeneratedPointerDrivingFunc.find(varName)) {
            return;
        }
        alreadyGeneratedPointerDrivingFunc.emplace(varName);
        symbolicFunc += typeName + " * makeSymbolicOfPointerMember" + varName + "()\n{\n";
        symbolicFunc += getIndent() + typeName + " *" + varName + " = new " + typeName + ";\n";
        debug && cout << "pointer of " << typeName << endl;
        for(auto inType : (*typeIter).second.m_fieldDecl) {
            // symbolicFunc += "    ";
            // symbolicFunc += inType.m_type + " " + inType.m_name + ";\n";
            symbolicFunc += getIndent() + "klee_make_symbolic(&(" + varName + "->" + inType.m_name + "), sizeof(" + inType.m_type + "), \"" + varName + "_" + inType.m_name + "\");\n";
        }
        symbolicFunc += getIndent() + "return " + varName + ";\n";
        symbolicFunc += "}\n";
    } else {
        debug && cout << "Oops, encountered an unknown type: " << typeName << endl;
    }
    debug && cout << symbolicFunc << endl;
}

void makeSymbolic(const DeclType &declType)
{
    debug && cout << "make_symbolic" << endl;
    static unsigned count = 0;
    std::string varName = "__" + to_string(++count) + "__";
    std::string klee = "\nint main()\n{\n";
    klee += getIndent() + declType.m_typeName + " " + varName + ";\n";
    klee += getIndent() + "klee_make_symbolic(&" + varName + ", sizeof(" + declType.m_typeName + "), \"" + varName + "\");\n";
    for(auto field : declType.m_fieldDecl) {
        if(field.m_isPointer) {
            debug && cout << "Get pointer type: " << field.m_type << " *" << field.m_name << ";" << endl;
            makeSymbolicOfPointerType(field);
            // klee += getIndent() + field.m_type + " " + field.m_name + ";\n";
            klee += getIndent() + varName + "." + field.m_name + " = make_symbolic__" + replace(field.m_type, ' ', '_') + "();\n";

        } else {
            // debug && cout << field.m_type << " " << field.m_name << endl;
            // klee += getIndent() + "klee_make_symbolic(&(" + varName + "." + field.m_name + "), sizeof(" + field.m_type + "), \"" + field.m_name + "\");\n";
        }
    }
    klee += getIndent() + "return 0;\n}\n";
    debug && cout << klee << endl;
}

/**
 * 对结构体进行符号化
 * 普通成员变量，直接符号化
 * 指针类型的成员变量，在堆上开辟空间，符号化指针指向的数据对象，并返回数据对象的指针
 * 针对指向的数据对象的类型不同：
 *     区分内置类型和自定义类型
 *     针对自定义类型：
 *         如果指向不同类型的对象，则继续递归
 *         如果指向同类型的对象，递归规定次数就截止
 */
void assumePointerMember(std::string &symbolicFunc, std::vector<std::string> &parent, const DeclType &declType)
{ // DFS + 回溯
    debug && cout << "=========================> assumePointerMember" << endl;
    for(auto &field : declType.m_fieldDecl) {
        if(field.m_isPointer) {
            std::string tmpVar = "__" + replace(project.m_alias2RealType[field.m_type], ' ', '_');
            std::string varName;
            for(auto &mem : parent) {
                varName += mem + ".";
            }
            if(field.m_isFundamentalType) {
                // TO-DO: DONE
                // symbolicFunc += getIndent() + field.m_type + " *_p_" + field.m_name + " = new " + field.m_type + ";\n";
                symbolicFunc += getIndent() + "klee_assume(" + varName + field.m_name + " == new " + field.m_type + ");\n";
                continue;
            }
            symbolicFunc += getIndent() + "klee_assume(" + varName + field.m_name + " == make_symbolic_of" + tmpVar + "());\n";
            debug && cout << "============> isPointer -----" << endl;
        } else if(field.hasPointerMember()) {
            parent.emplace_back(field.m_name);
            assumePointerMember(symbolicFunc, parent, types[field.m_type]);
            parent.pop_back();
            debug && cout << "===================> hasPointerMember +++++" << endl;
        }
    }
}

void makeSymbolicOfDecltype(const DeclType &declType)
{
    debug && cout << "makeSymbolicOfDecltype: " << declType.m_typeName << endl;
    std::string symbolicFunc = "\n";;
    std::string typeName = "struct " + declType.m_typeName;
    std::string varName = "__" + replace(typeName, ' ', '_');
    std::string declaring = typeName + " * make_symbolic_of" + varName + "();\n";
    symbolicFunc += typeName + " * make_symbolic_of" + varName + "()\n{\n";
    symbolicFunc += getIndent() + typeName + " *" + varName + " = new " + typeName + ";\n";
    symbolicFunc += getIndent() + "klee_make_symbolic(" + varName + ", sizeof(" + typeName + "), \"" + varName + "\");\n";
    if(declType.m_hasPointerMember) {
        std::vector<std::string> parent;
        parent.emplace_back("(*" + varName + ")");
        for(const auto &field : declType.m_fieldDecl) {
            if(field.m_isPointer) {
                if(field.m_isFundamentalType) {
                    // TO-DO: DONE
                    // symbolicFunc += getIndent() + field.m_type + " *_p_" + field.m_name + " = new " + field.m_type + ";\n";
                    symbolicFunc += getIndent() + "klee_assume(" + varName + "->" + field.m_name + " == new " + field.m_type + ");\n";
                    continue;
                }
                std::string tmpVar = "__" + replace(project.m_alias2RealType[field.m_type], ' ', '_');
                debug && cout << "alias " + field.m_type + " of " + tmpVar << endl;
                symbolicFunc += getIndent() + "klee_assume(" + varName + "->" + field.m_name + " == make_symbolic_of" + tmpVar + "());\n";
            } else if(field.hasPointerMember()) {
                parent.emplace_back(field.m_name);
                assumePointerMember(symbolicFunc, parent, types[field.m_type]);
                parent.pop_back();
            }
        }
    }
    symbolicFunc += getIndent() + "printf(\"------>" + varName + "_%p\\n\", " + varName + ");\n";
    symbolicFunc += getIndent() + "return " + varName + ";\n}\n";
    // debug && cout << symbolicFunc << endl;
    symbolicFuncs[varName] = symbolicFunc;
    declarings.emplace_back(declaring);
}

void procFuncBody(const clangmm::Cursor &compoundStmtCursor)
{
    debugFunc && cout << "------------------ procFuncBody()" << endl;
    queue<clangmm::Cursor> q;
    q.emplace(compoundStmtCursor);
    static int index = 0;
    while(!q.empty()) {
        clangmm::Cursor curFront = q.front();
        q.pop();
        
        if(curFront.get_kind() == clangmm::Cursor::Kind::CallExpr) {
            std::string returnType = curFront.get_type_description();
            std::string returnValueName = "retVal_" + to_string(index++);
            std::string returnValueDefination = returnType + " " + returnValueName + ";";
            debugFunc && cout << returnValueDefination << endl;
            std::string funcName = curFront.get_spelling();
            char mockTemplate[] = "MOCKER(%s).defaults().will(returnValue(%s);";
            char mockCode[100];
            sprintf(mockCode, mockTemplate, funcName.c_str(), returnValueName.c_str());
            std::string mocker(mockCode);
            debugFunc && cout << mocker << endl;
        }

        for(auto curTmp : curFront.get_children()) {
            q.emplace(curTmp);
        }
    }
}

bool getCompoundStmt(const clangmm::Cursor &funcCursor, clangmm::Cursor &compoundStmtCursor)
{
    std::vector<clangmm::Cursor> child = funcCursor.get_children();
    auto it = find_if(child.cbegin(), child.cend(), [](clangmm::Cursor cursor){
        return cursor.get_kind() == clangmm::Cursor::Kind::CompoundStmt;
    });
    compoundStmtCursor = *it;
    return it != child.cend();
}

void procFuncDecl(const clangmm::Cursor &funcDecl)
{
    // clangmm::Cursor compoundStmtCursor;
    // if(getCompoundStmt(funcDecl, compoundStmtCursor)) {
    //     procFuncBody(compoundStmtCursor);
    // }

    std::string returnType = clangmm::Cursor::Type(clang_getResultType(funcDecl.get_type().cx_type)).get_spelling();
    std::string funcName = funcDecl.get_token_spelling();
    std::string funcDeclaring = returnType + " " + funcDecl.get_display_name() + ";";
    if(project.m_funcInArgs.cend() != project.m_funcInArgs.find(funcDeclaring)) {
        return;
    }
    // debugFunc && cout << "funcDecl: " << funcDeclaring << endl;
    // debug && cout << funcDecl << endl;
    // debug && cout << funcDecl.get_semantic_parent().get_kind_spelling() << endl;
    // debug && cout << funcDecl.get_source_location().get_path() << endl;
    // debug && cout << funcDecl.get_spelling() << endl;
    // debug && cout << funcDecl.get_type_description() << endl;
    // debug && cout << funcDecl.get_definition() << endl;
    project.m_funcInArgs[funcDeclaring] = {};
    project.m_funcReturnTypeAndName[funcDeclaring] = std::make_pair(returnType, funcName);
    auto args = funcDecl.get_arguments();
    // debugFunc && cout << "arguments:" << endl;
    for(auto arg : args) {
        auto type = arg.get_type().get_spelling();
        auto name = arg.get_spelling();
        project.m_funcInArgs[funcDeclaring].emplace_back(std::make_pair(type, name));
    // debugFunc && cout << "funcDecl: " << funcDeclaring << endl;
        // debugFunc && cout << getIndent() << type + " " + name + ";"<< endl;
    }
}

void constructSymbolicDrivingMainFunc(const std::string &funcDeclaring, const std::vector<std::pair<std::string, std::string>> &args)
{
    // debugFunc && cout << "funcDecl: " << funcDeclaring << endl;
    // debugFunc && cout << "arguments:" << endl;
    std::string drivingMainFunc = "\nint main()\n{\n";
    for(const auto &arg : args) {
        // debugFunc && cout << getIndent() << arg.first + " " + arg.second + ";"<< endl;
        // TO-DO: 指针类型的入参
        FieldDecl fieldDecl;
        if(arg.first.back() == '*') {
            fieldDecl.m_isPointer = true;
            fieldDecl.m_type = project.m_alias2RealType[arg.first.substr(0, arg.first.length() - 2)];
        } else {
            fieldDecl.m_type = project.m_alias2RealType[arg.first];
        }
        fieldDecl.m_name = arg.second;
        if(fundamentalType.cend() != fundamentalType.find(fieldDecl.m_type)) {
            fieldDecl.m_isFundamentalType = true;
        }
        if(fieldDecl.m_isFundamentalType) {
            if(fieldDecl.m_isPointer) {
                drivingMainFunc += getIndent() + fieldDecl.m_type + " *" + arg.second + " = new " + fieldDecl.m_type + ";\n";
                drivingMainFunc += getIndent() + "klee_make_symbolic(" + arg.second + ", sizeof(" + fieldDecl.m_type + "), \"" + arg.second + "\");\n";
            } else {
                drivingMainFunc += getIndent() + fieldDecl.m_type + " " + arg.second + ";\n"; 
                drivingMainFunc += getIndent() + "klee_make_symbolic(&" + arg.second + ", sizeof(" + fieldDecl.m_type + "), \"" + arg.second + "\");\n";
            }
        } else {
            if(fieldDecl.m_isPointer) {
                drivingMainFunc += getIndent() + fieldDecl.m_type + " " + arg.second + " = make_symbolic_of__" + replace(fieldDecl.m_type, ' ', '_') + "();\n"; 
            } else {
                drivingMainFunc += getIndent() + fieldDecl.m_type + " " + arg.second + " = *make_symbolic_of__" + replace(fieldDecl.m_type, ' ', '_') + "();\n"; 
            }
        }
    }
    std::string callExpr = getIndent() + project.m_funcReturnTypeAndName[funcDeclaring].second + "(";
    for(const auto &arg : args) {
        callExpr += arg.second + ", ";
    }
    callExpr = callExpr.substr(0, callExpr.length() - 2) + ");\n";
    drivingMainFunc += callExpr; 
    drivingMainFunc += getIndent() + "return 0;\n}\n";
    debugFunc && cout << drivingMainFunc << endl;
}

int main()
{
    // clang++ -fsyntax-only -Xclang -ast-dump azt.cc
    vector<clangmm::Cursor> typedefDeclVec;
    vector<clangmm::Cursor> structDeclVec;
    vector<clangmm::Cursor> funcDeclVec;
    // vector<clangmm::Cursor> compoundStmtVec;
    std::string filepath = "sym_file.cc";
    project.m_projectName = filepath;

    clangmm::TranslationUnit tu(std::make_shared<clangmm::Index>(0, 0), filepath, {});
    clangmm::Cursor cursor = tu.get_cursor();

    queue<clangmm::Cursor> q; // AST并不是严格的树形结构，其中也会有回路，所以需要找替代方案，加个标记
    q.emplace(cursor);
    while(!q.empty()) {
        clangmm::Cursor curFront = q.front();
        q.pop();
        // debug && cout << curFront.get_token_spelling() << endl;
        // debug && cout << "Path: " << curFront.get_source_location().get_path() << endl;

        if(curFront.get_source_location().get_path() == filepath) {
            // debug && cout << curFront.get_kind_spelling() << endl;
            if(curFront.get_kind() == clangmm::Cursor::Kind::FunctionDecl) {
                funcDeclVec.emplace_back(curFront);
            }

            if(curFront.get_kind() == clangmm::Cursor::Kind::TypedefDecl || curFront.get_kind() == clangmm::Cursor::Kind::TypeAliasDecl) {
                typedefDeclVec.emplace_back(curFront);
            }

            if(curFront.get_kind() == clangmm::Cursor::Kind::StructDecl) {
                structDeclVec.emplace_back(curFront);
            }
        }

        for(const auto &curTmp : curFront.get_children()) {
            q.emplace(curTmp);
        }
    }

    for(const auto &typedefDecl : typedefDeclVec) {
        std::string alias = typedefDecl.get_spelling();
        std::string underlyingType = clangmm::Cursor::Type(clang_getTypedefDeclUnderlyingType(typedefDecl.cx_cursor)).get_spelling();
        debug && cout << alias << "'s realType ==> " << underlyingType << endl;
        project.m_alias2RealType.emplace(alias, underlyingType);
        project.m_alias2RealType.emplace(underlyingType, underlyingType);
        project.m_alias2RealType.emplace(underlyingType.substr(7), underlyingType);
    }

    for(const auto &typer : fundamentalType) { // 兼容内置类型
        project.m_alias2RealType.emplace(typer, typer);
        // DeclType declType;
        // declType.m_isFundamentalType = true;
        // declType.m_typeName = typer;
        // project.m_declTypesMap[typer] = declType;
        // project.m_declTypesMap[typer + " *"] = declType;
    }

    for(const auto &funcDecl : funcDeclVec) {
        procFuncDecl(funcDecl);
    }

    std::unordered_set<std::string> selfDefinedType;

    for(const auto &structure : structDeclVec) {
        std::string typeName = structure.get_type_description();
        if(selfDefinedType.cend() == selfDefinedType.find(typeName)) {
            debug && cout << "add " << typeName << endl;
            selfDefinedType.emplace(typeName);
            procStructDecl(structure);
        }
    }

    for(const auto &alias : project.m_alias2RealType) {
        types.emplace(alias.first, types[alias.second]);
    }
    
    // for(auto &declType : project.m_declTypes) { // 为什么用set的时候默认返回的是const引用？因为set容器内的元素只读，不可修改
    for(auto &declType : project.m_declTypes) {
        if(hasPointerMemberOfType.cend() == hasPointerMemberOfType.find(declType.m_typeName)) {
            // hasPointerMemberOfType[declType.m_typeName] = findAndMarkPointerMember(const_cast<DeclType&>(declType));
            hasPointerMemberOfType[declType.m_typeName] = findAndMarkPointerMember(declType);
            declType.m_hasPointerMember && debug && cout << declType.m_typeName << " ------------ has pointer member-----------" << endl;
        }
        // declType.m_hasPointerMember = true;
    }

    int count = 0;
    for(const auto &declType : project.m_declTypes) {
        count++;
        debug && cout << endl << count << "th declType:" << endl;
        debug && cout << declType << endl;

        // project.m_declTypesMap[declType.m_typeName] = declType;

        // makeSymbolic(declType);
        if(alreadyGeneratedStructDrivingFunc.cend() == alreadyGeneratedStructDrivingFunc.find(declType.m_typeName)) {
            makeSymbolicOfDecltype(declType);
            alreadyGeneratedStructDrivingFunc.emplace(declType.m_typeName); // 不需要了
        }
    }

    for(const auto &declaring : declarings) {
        cout << declaring;
    }

    for(const auto &symbolicFunc : symbolicFuncs) {
        cout << symbolicFunc.second;
    }

    cout << endl;

    for(const auto &func : project.m_funcInArgs) {
        constructSymbolicDrivingMainFunc(func.first, func.second);
    }

    // std::unordered_set<DeclType> declTypes;
    // std::set<DeclType> declTypes;

    return 0;
}
